#pragma once

#pragma unmanaged

#include <BWSAL\BuildType.h>

#pragma managed

#include "..\BWAPI\Tech.h"
#include "..\BWAPI\Unit.h"
#include "..\BWAPI\UnitType.h"
#include "..\BWAPI\Upgrade.h"
#include "Enum\BuildType.h"

using namespace System;
using namespace System::Collections::Generic;
using namespace BroodWar::Api;
using namespace BroodWar::Api::Enum;

namespace BroodWar
{
	namespace Addon
	{
		public ref class Build : IIdentifiedObject
		{
		internal:
			bool dispose;
			BWSAL::BuildType* instance;

			Build(BWSAL::BuildType type);
			Build(BWSAL::BuildType* type);
			~Build();
			!Build();
		public:
			Build();
			Build(int id);
			Build(Build^ other);
			Build(Tech^ other);
			Build(Api::UnitType^ other);
			Build(Api::Enum::UnitType other);
			Build(Upgrade^ other);
			Build(Upgrade^ other, int level);
			Build(UpgradeType other);
			Build(UpgradeType other, int level);

			virtual property int Id { int get(); }
			property BuildType Type { BuildType get(); }
			bool TypeEquals(BuildType buildType);
			property Api::Race^ Race { Api::Race^ get(); }
			
			property bool IsTechType { bool get(); }
			property bool IsUnitType { bool get(); }
			property bool IsUpgradeType { bool get(); }
			property Api::Tech^ Tech { Api::Tech^ get(); }
			property Api::UnitType^ UnitType { Api::UnitType^ get(); }
			property Api::Upgrade^ Upgrade { Api::Upgrade^ get(); }
			property int UpgradeLevel { int get(); }
			property unsigned int Mask { unsigned int get(); }
			property unsigned int RequiredMask { unsigned int get(); }

			property Tuple<Build^, int>^ WhatBuilds { Tuple<Build^, int>^ get(); }
			property Dictionary<Build^, int>^ RequiredBuildTypes { Dictionary<Build^, int>^ get(); }

			property bool RequiresPsi { bool get(); }
			property bool RequiresLarva { bool get(); }
			property Build^ RequiredAddon { Build^ get(); }
			property int MineralPrice { int get(); }
			property int GasPrice { int get(); }
			property int BuilderTime { int get(); }
			property int BuildUnitTime { int get(); }
			property int PrepTime { int get(); }
			property bool CreatesUnit { bool get(); }
			property bool MorphsBuilder { bool get(); }
			property bool NeedsBuildLocation { bool get(); }
			property int SupplyRequired { int get(); }
			property int SupplyProvided { int get(); }

			bool DoBuild(Unit^ builder, Unit^ secondBuilder, TilePosition^ buildLocation);
			bool IsPreparing(Unit^ builder, Unit^ secondBuilder);
			bool IsBuilding(Unit^ builder, Unit^ secondBuilder, Unit^ createdUnit);
			bool IsCompleted(Unit^ builder, Unit^ secondBuilder, Unit^ createdUnit, Unit^ secondCreatedUnit);
			int RemainingTime(Unit^ builder, Unit^ secondBuilder, Unit^ createdUnit);

			virtual int GetHashCode() override;
			virtual bool Equals(Object^ o) override;
			virtual String^ ToString() override;
			bool Equals(Build^ other);

			static HashSet<Build^>^ AllBuildTypes();
			static HashSet<Build^>^ AllBuildTypes(Api::Race^ race);
			static HashSet<Build^>^ AllRequiredBuildTypes();
			static HashSet<Build^>^ AllRequiredBuildTypes(Api::Race^ race);

			static property unsigned int WorkerMask { unsigned int get(); }
			static property unsigned int RefineryMask { unsigned int get(); }
			static property unsigned int SupplyMask { unsigned int get(); }
			static property unsigned int CenterMask { unsigned int get(); }

			static bool operator == (Build^ first, Build^ second);
			static bool operator != (Build^ first, Build^ second);
			static bool operator == (Build^ first, Api::UnitType^ second);
			static bool operator == (Build^ first, Api::Enum::UnitType second);
			static bool operator == (Build^ first, Api::Tech^ second);
			static bool operator == (Build^ first, Api::Upgrade^ second);
			static bool operator == (Build^ first, UpgradeType second);
			static bool operator < (Build^ first, Build^ second);
		};

		Build^ ConvertBuild(BWSAL::BuildType* build);
		Build^ ConvertBuild(BWSAL::BuildType build);
		BWSAL::BuildType ConvertBuild(Build^ build);
		BWSAL::BuildType ConvertBuild(BuildType build);
	}
}
